# docstring
__version__ = "$Revision: 66 $"
# $Id: views.py 66 2008-08-31 22:26:38Z AxisOfEntropy $

# Create your views here.
from cv.models import *
from django.views.generic import list_detail, simple, create_update

from django.http import HttpResponse, HttpResponseRedirect #To manual form our own responses for files

from django.core.urlresolvers import reverse #For redirection based on view name

from django.conf import settings

# SOAP is awesomesauce, we use it here to query the Europass web services so they can generate CV documents in other formats from our generated XML.
from SOAPpy import WSDL

# This constant will be passed to WSDL.Proxy() instances.
# Perhaps this constant should be in settings.py?
EUROPASS_WSDL_FILE = 'http://europass.cedefop.europa.eu/instrumentssrv/services/Instruments?wsdl'

def learnerInformation_xml_v12(request, id, template_name="europassCV_V1.2.xml"):
    '''Return the requested Resume/CV as Europass standardized XML, wrapper for generic view'''
    #Note that the relevant XSL must be served from the same hostname for many browsers to accept it.
    return list_detail.object_detail(
        request,
        queryset=LearnerInformation.objects.all(),
        object_id=id,
        template_name = template_name,
        mimetype = "application/xml",
    )

def learnerInformation_html_v12(request, object_id, template_name='europassCV_V1.2.xml', extra_context={}):
    '''Return the requested resume/CV rendered in HTML'''
    # Much of this view taken from examle at http://xmlsoft.org/XSLT/python.html
    import libxml2
    import libxslt
    
    # Load the appropriate stylesheet for this LearnerInformation's locale
    locale = LearnerInformation.objects.get(id=object_id).locale
    stylesheet_file = settings.STATIC_ROOT + "europass-xsl/cv_%s.xsl" % locale
    styledoc = libxml2.parseFile(stylesheet_file)
    style = libxslt.parseStylesheetDoc(styledoc)
    
    # Fetch and load the XML we're about to render
    xmlString = learnerInformation_xml_v12(request, id=object_id, template_name=template_name).content
    doc = libxml2.parseDoc(xmlString)
    
    # Apply the XSL to the XML
    result = style.applyStylesheet(doc, None)
    result_string = str(result)
    
    # Cleanup
    #style.freeStylesheet()
    styledoc.freeDoc()
    doc.freeDoc()
    result.freeDoc()
    
    # Return the resulting HTML string as a response.
    return HttpResponse(result_string)

def getDocumentFromEuropass(request, id, format='pdf', locale='', file_base_name=None, content_type=None):
    '''An intermediate function that generates a Europass standard XML document, then fetches a formatted document from Europass via a SOAP web service.  Returns the an HttpResponse or raises an exception.'''
    xmlFile = learnerInformation_xml_v12(request, id).content
    server = WSDL.Proxy(EUROPASS_WSDL_FILE)
    #try:
    result = server.getDocumentFromCV(xmlFile, format, locale).decode('hex')
    #except:
    response = HttpResponse(result)
    response['Content-Length'] = len(result)
    
    # If a filename was specified, add it to the response headers, otherwise use the object's id.
    if file_base_name:
        response['Content-Disposition'] = 'attachment; filename='+file_base_name+'.'+format
    else:
        response['Content-Disposition'] = 'attachment; filename='+id+'.'+format
    
    # If a MIME type was specified, add that to the response headers.
    if content_type:
        response['Content-Type'] = content_type
    return response
    
def learnerInformation_pdf(request, id):
    """Return the specified CV as an Adobe PDF document, generated by the Europass webservice."""
    response = getDocumentFromEuropass(request, id, 'pdf')
    response['Content-Type'] = 'application/pdf'
    return response
    
def learnerInformation_doc(request, id):
    """Return the specified CV as an Microsoft Word document, generated by the Europass webservice."""
    response = getDocumentFromEuropass(request, id, 'doc')
    response['Content-Type'] = 'application/msword'
    return response
    
def learnerInformation_odt(request, id):
    """Return the specified CV as an OpenOffice ODT document, generated by the Europass webservice."""
    response = getDocumentFromEuropass(request, id, 'odt')
    response['Content-Type'] = 'application/vnd.oasis.opendocument.text'
    return response
    
def learnerInformation_create(request, template_name="learnerinformation_form.html", post_save_redirect=None):
    """Much of this was stolen from http://www.djangosnippets.org/snippets/582/"""
    from django.shortcuts import render_to_response
    from cv.forms import LearnerInformationBasicForm
    if request.POST:
        form = LearnerInformationBasicForm(request.POST)
        if form.is_valid():
            object_created = form.save()
            if post_save_redirect:
                # If a post-save redirect URL is specified, redirect users to it.  Otherwise, redirect them to the update page for the object they've just created.
                return HttpResponseRedirect(post_save_redirect)
            else:
                return HttpResponseRedirect(reverse('learnerInformation_update', kwargs={'object_id': object_created.id}))
    else:
        form = LearnerInformationBasicForm()
    
    context = {'form':form, 'add':True, 'post':request.POST}
     
    return render_to_response(template_name, dictionary=context)
    
def learnerInformation_update(request, object_id, template_name="learnerinformation_form.html", extra_context={}, form='all', tab_list=None):
    """Render a form to update most of a LearnerInformation object.
        Much of this was stolen from http://www.djangosnippets.org/snippets/582/"""
    from django.shortcuts import render_to_response, get_object_or_404
    from cv.forms import *
    
    object = get_object_or_404(LearnerInformation, pk=object_id)

    # Keep here a list of the subform classes we can render
    subforms = {
        'all': LearnerInformationForm,
        'basic': LearnerInformationBasicForm,
        'address': LearnerInformationAddressForm,
        'contact': LearnerInformationContactForm,
        'skills': LearnerInformationSkillsForm,
        'additional': LearnerInformationAdditionalForm,
    }
    
    #If the incoming POST request has any of the fields in the LearnerInformationForm, use this to validate and populate the form.
    if set(request.POST.keys()) & set(LearnerInformationForm.base_fields.keys()): # Thank you #python @ freenode!
        # Instantiate the specified form (chosing from the dictionary)
        form = subforms[form](request.POST, instance=object)
        if form.is_valid():
            object_update = form.save()
            
    else:
        form = subforms[form](instance=object)
    
    # If we haven't been passed a list of tabs to render, guess.
    if not tab_list:
        tab_list = subforms.keys()

    context = {'form':form, 'add':True, 'post':request.POST, 'body_id': form, 'tab_list': tab_list,}
    context.update(extra_context)
     
    return render_to_response(template_name, dictionary=context)

def learnerInformation_work_update(request, object_id, template_name="inline_formset.html", extra_context={}, tab_list=['all',], form='work'):
    """Render a formset for editing multiple instances of WorkExperience, tied to the LearnerInformation specificed by object_id."""
    from django.shortcuts import render_to_response, get_object_or_404
    from django.forms.models import inlineformset_factory
    from cv.forms import FacebookModelForm, FacebookBaseInlineFormset, WorkExperienceForm
    WorkExperienceFormSet = inlineformset_factory(LearnerInformation, 
                            WorkExperience, form=WorkExperienceForm,
                            formset=FacebookBaseInlineFormset,
                            extra=1)
    
    object = get_object_or_404(LearnerInformation, pk=object_id)

    if request.POST.has_key('workexperience_set-INITIAL_FORMS'):
        formset = WorkExperienceFormSet(request.POST, instance=object)
        if formset.is_valid():
            instances = formset.save()
    else:
        formset = WorkExperienceFormSet(instance=object)
    
    context = {'formset': formset, 'post': request.POST, 'body_id': form, 'tab_list': tab_list, }
    context.update(extra_context)
    
    return render_to_response(template_name, dictionary=context)

def learnerInformation_education_update(request, object_id, template_name="inline_formset.html", extra_context={}, tab_list=['all',], form='education'):
    """Render a formset for editing multiple instances of Education, tied to the LearnerInformation specificed by object_id."""
    from django.shortcuts import render_to_response, get_object_or_404
    from django.forms.models import inlineformset_factory
    from cv.forms import FacebookModelForm, FacebookBaseInlineFormset, EducationForm
    FormSetType = inlineformset_factory(LearnerInformation, Education, 
            form=EducationForm, formset=FacebookBaseInlineFormset,
            extra=1)
    
    object = get_object_or_404(LearnerInformation, pk=object_id)

    if request.POST.has_key('education_set-INITIAL_FORMS'):
        formset = FormSetType(request.POST, instance=object)
        if formset.is_valid():
            instances = formset.save()
    else:
        formset = FormSetType(instance=object)
    
    context = {'formset': formset, 'post': request.POST, 'body_id': form, 'tab_list': tab_list, }
    context.update(extra_context)
    
    return render_to_response(template_name, dictionary=context)
    
def learnerInformation_photo_update(request, object_id, template_name="photo_update.html", extra_context={}, tab_list=['all',], form='photo', post_save_redirect='.'):
    """Wraps a generic view for modifying Photo object of the LearnerInformation specified by object_id, creating a Photo object if needed."""
    from django.shortcuts import render_to_response, get_object_or_404

    L = get_object_or_404(LearnerInformation, pk=object_id)
    if not L.photo_id:
        p = Photo()
        p.save()
        L.photo = p
        L.save()
    
    extra_context.update({'body_id': form, 'tab_list': tab_list, 'post': request.POST.copy(), })
    
    if not request.FILES:
        from cv.forms import PhotoForm
        extra_context.update({'form': PhotoForm(), 'object': L.photo })
        return render_to_response(
            template_name=template_name,
            dictionary=extra_context,
        )
    else:
        return create_update.update_object(
            request, model=Photo,
            object_id=L.photo_id,
            template_name=template_name,
            extra_context=extra_context,
            post_save_redirect=post_save_redirect,
        )

def learnerInformation_american_convert(request, object_id,
                service_url="http://localhost:8080/converter/service",
                mimetype='application/pdf', format='pdf', 
                file_base_name='resume'):
    """Make an HTTP request to JODConverter service, POSTing an ODT
    document and recievinng another document, to be returned to the end user.
    TODO: This should certainly be abstracted to handle more than one format.
    """
    from urllib2 import Request, urlopen
    
    # Fetch an ODT for this object_id
    # L = get_object_or_404(LearnerInformation, pk=object_id)
    response = learnerInformation_american_odt(request, object_id)
    data = response.content
    
    # Prepare the HTTP request
    req = Request(service_url)
    req.add_header('Content-Type', 'application/vnd.oasis.opendocument.text')
    req.add_header('Accept', mimetype)
    
    # Execute the HTTP request
    r = urlopen(req, data)
    
    # Prepare our response
    response = HttpResponse(r.read())
    response['Content-Type'] = mimetype
    response['Content-Disposition'] = \
        'attachment; filename='+file_base_name+'.'+format

    # Close up and return the response to the end user
    r.close()
    return response

def learnerInformation_american_odt( request, object_id, 
                    template_name="/var/www/europass/django-project/cv/templates/learnerinformation.odt", 
                                                    extra_context={} ):
    """
      template_name - path to the template document, must be ODT
      context - dictionary to create context from
      This was borrowed from http://www.djangosnippets.org/snippets/15/
    """
    import zipfile
    import StringIO
    from django.template import Context, Template
    from django.shortcuts import get_object_or_404
    
    L = get_object_or_404(LearnerInformation, pk=object_id)
    extra_context.update({'object': L})
    
    c = Context()
    for key, value in extra_context.items():
        if callable( value ):
            c[key] = value()
        else:
            c[key] = value

    # default mimetype
    mimetype = 'application/vnd.oasis.opendocument.text'
    # ODF is just a zipfile
    input = zipfile.ZipFile( template_name, "r" )
    # we cannot write directly to HttpResponse, so use StringIO
    text = StringIO.StringIO()
    # output document
    output = zipfile.ZipFile( text, 'w' )

    # go through the files in source
    for zi in input.filelist:
        out = input.read( zi.filename )
        # wait for the only interesting file
        if zi.filename == 'content.xml':
            # un-escape the quotes (in filters etc.)
            t = Template( out.replace( '&quot;', '"' ) ) 
            # render the document
            out = t.render( c ) 
        elif zi.filename == 'mimetype':
            # mimetype is stored within the ODF
            mimetype = out 
        if isinstance(out, unicode):
            output.writestr( zi.filename, out.encode('ascii', 'xmlcharrefreplace') )
        else:
            output.writestr( zi.filename, str(out))

    # close and finish
    output.close()
    input.close()
    content=text.getvalue()
    text.close()
    return HttpResponse( content=content, mimetype=mimetype )
